#pragma once

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "../comm/util.hpp"
#include "../comm/log.hpp"


namespace ns_compiler
{
    using namespace ns_util;
    using namespace ns_log;

    class Compiler
    {
    public:
        Compiler() {}
        ~Compiler(){}

        /*
        * Compile 编译函数        
        * 参数：一个文件名，该文件名不需要后缀
        * 返回值：编译成功返回true，否则返回false
        */
        static bool Compile(const std::string& file_name)
        {
            pid_t pid = fork();
            if( pid < 0 )
            {
                LOG(ERROR) << "内部错误，编译时创建子进程失败" << "\n";
                return false;
            }
            else if( 0 == pid )
            {
                // 子进程 
                /* 让子进程执行编译过程，即使编译出错，不会影响父进程，也就是我们的主进程 */
                umask(0);
                int sub_stderr_fd = open(PathUtil::CompilerError(file_name).c_str(), O_CREAT|O_WRONLY, 0644);
                if( sub_stderr_fd < 0 )
                {
                    LOG(WARNING) << "内部错误，没有成功形成用户提交程序的标准错误文件" << "\n";
                    exit(1);
                }
                // 将用户提交程序的标准错误重定向到 该文件中，用户的程序编译失败，可以将该文件中的内容返回给用户
                dup2( sub_stderr_fd, 2);

                // 通过程序替换 让子进程去编译用户提交的程序
                execlp("g++","g++", "-o",PathUtil::Exe(file_name).c_str(), PathUtil::Src(file_name).c_str(),"-std=c++11",  "-D", "COMPILER_ONLINE","-std=c++11", nullptr);
                
                LOG(ERROR) << "内部错误，编译用户程序时，启动g++失败，可能是 “参数错误” " << "\n";
                exit(2);
            }
            else if( pid > 0 )
            {
                // 父进程
                waitpid(pid, nullptr, 0);
                if( FileUtil::IsFileExists(PathUtil::Exe(file_name)) )
                {
                    LOG(INFO) << "用户程序编译成功: " << PathUtil::Src(file_name).c_str() << "\n";
                    return true;
                }
            }

            LOG(ERROR) << "用户程序编译失败，没有形成可执行程序" << "\n";
            return false;
        }
    };
}// namespace ns_compiler